package models;

import play.Logger;
import play.cache.Cache;
import play.db.jpa.Model;
import play.mvc.Scope;

import java.util.Random;

/**
 * The board model. Handles all game actions and status. 
 */
public class Board extends Model
{
	/**
	 * A private variable to store the status of a game.
	 */
    private char boxes[] = new char[9];
	/**
	 * A counter for done moves in a game.
	 */
    private char countMarks;

    public Board()
    {
        initBoard();
    }

	/*
	 * Getters and setters for private variables
	 */
    public char[] getBoxes()
    {
        return boxes;
    }

    public void setBoxes(int i, char mark)
    {
        if (boxes[i] == '-') {
            boxes[i] = mark;
            countMarks++;
        }
    }

    public char getMark(int i)
    {
        return boxes[i];
    }

    public boolean isFull()
    {
        return ( (9 - countMarks) == 0 );
    }

	/**
	 * This method initializes the bord model to default values.
	 */
    public void initBoard()
    {
       for (int i = 0; i < 9; i++) {
            boxes[i] = '-';
	   }
       countMarks = 0;
    }

	/**
	 * This method tries to get a Board object from the current session.
	 * If that fails it creates a new instance.
	 * @return	Board	An instance of the Board model
	 */
	public static Board getFromSession()
    {
		Scope.Session session = Scope.Session.current();
        Board myBoard = Cache.get(session.getId() + "-board", Board.class);
        if (myBoard == null) {
			myBoard = new Board();
            Cache.set(session.getId() + "-board", myBoard, "30mn" );
		}
        Logger.info(session.getId() + "-board");
        return myBoard;
    }

	/**
	 * This method returns the winner of the current game.
	 * It returns '-' if there is no winner yet or 'p' if the game is a draw.
	 * @return	char	The winner or '-' for no winner or 'p' for a draw.
	 */
    public char getWinner()
    {
		Board myBoard = this;
        if (myBoard.getMark(0) != '-') {
            //line 0 - 1 - 2
            if (myBoard.getMark(0) == myBoard.getMark(1) && myBoard.getMark(0) == myBoard.getMark(2))
                return myBoard.getMark(0);
            //line 0 - 3 - 6
            if (myBoard.getMark(0) == myBoard.getMark(3) && myBoard.getMark(0) == myBoard.getMark(6))
                return myBoard.getMark(0);
        }
        if (myBoard.getMark(8) != '-') {
            //line 8 - 5 - 2
            if (myBoard.getMark(8) == myBoard.getMark(5) && myBoard.getMark(8) == myBoard.getMark(2))
                return myBoard.getMark(8);
            //line 8 - 7 - 6
            if (myBoard.getMark(8) == myBoard.getMark(7) && myBoard.getMark(8) == myBoard.getMark(6))
                return myBoard.getMark(8);
        }

        if (myBoard.getMark(4) != '-') {
            //line from middle 1 - 4 - 7
            if (myBoard.getMark(4) == myBoard.getMark(1) && myBoard.getMark(4) == myBoard.getMark(7))
                return myBoard.getMark(4);
            //line from middle 3 - 4 - 5
            if (myBoard.getMark(4) == myBoard.getMark(3) && myBoard.getMark(4) == myBoard.getMark(5))
                return myBoard.getMark(4);
            //line from middle 6 - 4 - 2
            if (myBoard.getMark(4) == myBoard.getMark(6) && myBoard.getMark(4) == myBoard.getMark(2))
                return myBoard.getMark(4);
            //line from middle 0 - 4 - 8
            if (myBoard.getMark(4) == myBoard.getMark(0) && myBoard.getMark(4) == myBoard.getMark(8))
                return myBoard.getMark(4);
        }
		if (!isFull()) {
			return '-';
		}
		else {
			return 'p';
		}
    }

	/***
     * An algorithm used for deciding the computer game move
     * which is evaluated from the current game status stored in the board object
     * @return an integer which indicates the decided game move.
     */
   	public int getComputerMove()
    {
		Board myBoard = this;
        int n = -1;
        // X X -
        // X X -
        // X X -
        if(myBoard.getMark(0) == 'x' && myBoard.getMark(1) == 'x' && myBoard.getMark(2) == '-') {
            n = 2;
            return n;
        }
        else if (myBoard.getMark(3) == 'x' && myBoard.getMark(4) == 'x' && myBoard.getMark(5) == '-') {
            n = 5;
            return n;
        }
        else if (myBoard.getMark(6) == 'x' && myBoard.getMark(7) == 'x' && myBoard.getMark(8) == '-') {
            n = 8;
            return n;
        }
        // - X X
        // - X X
        // - X X
        else if (myBoard.getMark(1) == 'x' && myBoard.getMark(2) == 'x' && myBoard.getMark(0) == '-') {
            n = 1;
            return n;
        }
        else if (myBoard.getMark(4) == 'x' && myBoard.getMark(5) == 'x' && myBoard.getMark(3) == '-') {
            n = 3;
            return n;
        }
        else if (myBoard.getMark(7) == 'x' && myBoard.getMark(8) == 'x' && myBoard.getMark(6) == '-') {
            n = 6;
            return n;
        }
        // X - X
        // X - X
        // X - X
        else if (myBoard.getMark(0) == 'x' && myBoard.getMark(2) == 'x' && myBoard.getMark(1) == '-') {
            n = 1;
            return n;
        }
        else if (myBoard.getMark(3) == 'x' && myBoard.getMark(5) == 'x' && myBoard.getMark(4) == '-') {
            n = 4;
            return n;
        }
        else if (myBoard.getMark(6) == 'x' && myBoard.getMark(8) == 'x' && myBoard.getMark(7) == '-') {
            n = 7;
            return n;
        }
        // X X X
        // X X X
        // - - -
        else if (myBoard.getMark(0) == 'x' && myBoard.getMark(3) == 'x' && myBoard.getMark(6) == '-') {
            n = 6;
            return n;
        }
        else if (myBoard.getMark(1) == 'x' && myBoard.getMark(4) == 'x' && myBoard.getMark(7) == '-') {
            n = 7;
            return n;
        }
        else if (myBoard.getMark(2) == 'x' && myBoard.getMark(5) == 'x' && myBoard.getMark(8) == '-') {
            n = 8;
            return n;
        }
        // - - -
        // X X X
        // X X X
        else if (myBoard.getMark(3) == 'x' && myBoard.getMark(6) == 'x' && myBoard.getMark(0) == '-') {
            n = 0;
            return n;
        }
        else if (myBoard.getMark(4) == 'x' && myBoard.getMark(7) == 'x' && myBoard.getMark(1) == '-') {
            n = 1;
            return n;
        }
        else if (myBoard.getMark(5) == 'x' && myBoard.getMark(8) == 'x' && myBoard.getMark(2) == '-') {
            n = 2;
            return n;
        }
        // X X X
        // - - -
        // X X X
        else if (myBoard.getMark(0) == 'x' && myBoard.getMark(6) == 'x' && myBoard.getMark(3) == '-') {
            n = 3;
            return n;
        }
        else if (myBoard.getMark(1) == 'x' && myBoard.getMark(7) == 'x' && myBoard.getMark(4) == '-') {
            n = 4;
            return n;
        }
        else if (myBoard.getMark(2) == 'x' && myBoard.getMark(8) == 'x' && myBoard.getMark(5) == '-') {
            n = 5;
            return n;
        }
        // - X X
        // X - X
        // X X -
        else if (myBoard.getMark(4) == 'x' && myBoard.getMark(8) == 'x' && myBoard.getMark(0) == '-') {
            n = 0;
            return n;
        }
        else if (myBoard.getMark(0) == 'x' && myBoard.getMark(8) == 'x' && myBoard.getMark(4) == '-') {
            n = 4;
            return n;
        }
        else if (myBoard.getMark(0) == 'x' && myBoard.getMark(4) == 'x' && myBoard.getMark(8) == '-') {
            n = 8;
            return n;
        }
        // X X -
        // X - X
        // - X X
        else if (myBoard.getMark(4) == 'x' && myBoard.getMark(6) == 'x' && myBoard.getMark(6) == '-') {
            n = 6;
            return n;
        }
        else if (myBoard.getMark(6) == 'x' && myBoard.getMark(2) == 'x' && myBoard.getMark(4) == '-') {
            n = 4;
            return n;
        }
        else if (myBoard.getMark(6) == 'x' && myBoard.getMark(4) == 'x' && myBoard.getMark(2) == '-') {
            n = 2;
            return n;
        }
        // O O -
        // O O -
        // O O -
        else if (myBoard.getMark(0) == 'o' && myBoard.getMark(1) == 'o' && myBoard.getMark(2) == '-'){
            n = 2;
            return n;
        }
        else if (myBoard.getMark(3) == 'o' && myBoard.getMark(4) == 'o' && myBoard.getMark(5) == '-'){
            n = 5;
            return n;
        }
        else if (myBoard.getMark(6) == 'o' && myBoard.getMark(7) == 'o' && myBoard.getMark(8) == '-') {
            n = 8;
            return n;
        }
        // - O O
        // - O O
        // - O O
        else if (myBoard.getMark(1) == 'o' && myBoard.getMark(2) == 'o' && myBoard.getMark(0) == '-') {
            n = 0;
            return n;
        }
        else if (myBoard.getMark(4) == 'o' && myBoard.getMark(5) == 'o' && myBoard.getMark(3) == '-') {
            n = 3;
            return n;
        }
        else if (myBoard.getMark(7) == 'o' && myBoard.getMark(8) == 'o' && myBoard.getMark(6) == '-') {
            n = 6;
            return n;
        }
        // O - O
        // O - O
        // O - O
        else if (myBoard.getMark(0) == 'o' && myBoard.getMark(2) == 'o' && myBoard.getMark(1) == '-') {
            n = 1;
            return n;
        }
        else if (myBoard.getMark(3) == 'o' && myBoard.getMark(5) == 'o' && myBoard.getMark(4) == '-') {
            n = 4;
            return n;
        }
        else if (myBoard.getMark(6) == 'o' && myBoard.getMark(8) == 'o' && myBoard.getMark(7) == '-') {
            n = 7;
            return n;
        }
        // O O O
        // O O O
        // - - -
        else if (myBoard.getMark(0) == 'o' && myBoard.getMark(3) == 'o' && myBoard.getMark(6) == '-') {
            n = 6;
            return n;
        }
        else if (myBoard.getMark(1) == 'o' && myBoard.getMark(4) == 'o' && myBoard.getMark(7) == '-') {
            n = 7;
            return n;
        }
        else if (myBoard.getMark(2) == 'o' && myBoard.getMark(5) == 'o' && myBoard.getMark(8) == '-') {
            n = 8;
            return n;
        }
        // O O O
        // - - -
        // O O O
        else if (myBoard.getMark(0) == 'o' && myBoard.getMark(6) == 'o' && myBoard.getMark(3) == '-') {
            n = 3;
            return n;
        }
        else if (myBoard.getMark(1) == 'o' && myBoard.getMark(7) == 'o' && myBoard.getMark(4) == '-') {
            n = 4;
            return n;
        }
        else if (myBoard.getMark(2) == 'o' && myBoard.getMark(8) == 'o' && myBoard.getMark(5) == '-') {
            n = 5;
            return n;
        }
        // - - -
        // O O O
        // O O O
        else if (myBoard.getMark(3) == 'o' && myBoard.getMark(6) == 'o' && myBoard.getMark(0) == '-') {
            n = 0;
            return n;
        }
        else if (myBoard.getMark(4) == 'o' && myBoard.getMark(7) == 'o' && myBoard.getMark(1) == '-') {
            n = 1;
            return n;
        }
        else if (myBoard.getMark(5) == 'o' && myBoard.getMark(8) == 'o' && myBoard.getMark(2) == '-') {
            n = 2;
            return n;
        }
        // - O O
        // O - O
        // O O -
        else if (myBoard.getMark(0) == 'o' && myBoard.getMark(4) == 'o' && myBoard.getMark(8) == '-') {
            n = 8;
            return n;
        }
        else if (myBoard.getMark(0) == 'o' && myBoard.getMark(8) == 'o' && myBoard.getMark(4) == '-') {
            n = 4;
            return n;
        }
        else if (myBoard.getMark(4) == 'o' && myBoard.getMark(8) == 'o' && myBoard.getMark(0) == '-') {
            n = 0;
            return n;
        }
        // O O -
        // O - O
        // - O O
        else if (myBoard.getMark(4) == 'o' && myBoard.getMark(2) == 'o' && myBoard.getMark(6) == '-') {
            n = 6;
            return n;
        }
        else if (myBoard.getMark(6) == 'o' && myBoard.getMark(2) == 'o' && myBoard.getMark(4) == '-') {
            n = 4;
            return n;
        }
        else if (myBoard.getMark(6) == 'o' && myBoard.getMark(4) == 'o' && myBoard.getMark(2) == '-') {
            n = 2;
            return n;
        }
        else if (myBoard.getMark(0) == 'o' && myBoard.getMark(4) == 'x' && myBoard.getMark(8) == 'o') {
            n = 5;
            return n;
        }
        else if (myBoard.getMark(6) == 'o' && myBoard.getMark(4) == 'x' && myBoard.getMark(2) == 'o') {
            n = 3;
            return n;
        }
        else if (myBoard.getMark(4) == '-') {
            n = 4;
            return n;
        }
        else if (myBoard.getMark(0) == '-') {
            n = 0;
            return n;
        }
        else {
            Random generator = new Random();
            boolean generate = true;
            while (generate) {
                n = generator.nextInt(9);
                if ( myBoard.getMark(n) == '-' ) {
                    generate = false;
				}
            }
            Logger.info("Generated number: " + n);
            return n;
        }
    }
}
